using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using Microsoft.Practices.EnterpriseLibrary.Data;

namespace axCommerce.Data
{
	[DataObject]
	[Serializable]
	public partial class Account
	{
		#region Constants

		private const string TableName = "[dbo].[Account]";

		#endregion

		#region Properties

		public int? AccountId { get; set; }
		public string UserName { get; set; }
		public string Email { get; set; }
		public string Password { get; set; }
		public string PasswordSalt { get; set; }
		public DateTime? LastLoginDate { get; set; }
		public string LastLoginIp { get; set; }
		public bool? IsActivated { get; set; }
		public bool? IsLockedOut { get; set; }
		public DateTime? LastLockedOutDate { get; set; }
		public string LastLockedOutReason { get; set; }
		public string NewPasswordKey { get; set; }
		public DateTime? NewPasswordRequested { get; set; }
		public string NewEmail { get; set; }
		public string NewEmailKey { get; set; }
		public DateTime? NewEmailRequested { get; set; }
		public string Comments { get; set; }
		public DateTime? CreatedDate { get; set; }
		public DateTime? LastModifiedDate { get; set; }

		#endregion

		#region Methods

		#region Mapping Methods

		protected void MapTo(DataSet ds)
		{
			if (ds == null)
				ds = new DataSet();

			if (ds.Tables[TableName] == null)
				ds.Tables.Add(TableName);

			ds.Tables[TableName].Columns.Add("AccountId", typeof (Int32));
			ds.Tables[TableName].Columns.Add("UserName", typeof (String));
			ds.Tables[TableName].Columns.Add("Email", typeof (String));
			ds.Tables[TableName].Columns.Add("Password", typeof (String));
			ds.Tables[TableName].Columns.Add("PasswordSalt", typeof (String));
			ds.Tables[TableName].Columns.Add("LastLoginDate", typeof (DateTime));
			ds.Tables[TableName].Columns.Add("LastLoginIp", typeof (String));
			ds.Tables[TableName].Columns.Add("IsActivated", typeof (Boolean));
			ds.Tables[TableName].Columns.Add("IsLockedOut", typeof (Boolean));
			ds.Tables[TableName].Columns.Add("LastLockedOutDate", typeof (DateTime));
			ds.Tables[TableName].Columns.Add("LastLockedOutReason", typeof (String));
			ds.Tables[TableName].Columns.Add("NewPasswordKey", typeof (String));
			ds.Tables[TableName].Columns.Add("NewPasswordRequested", typeof (DateTime));
			ds.Tables[TableName].Columns.Add("NewEmail", typeof (String));
			ds.Tables[TableName].Columns.Add("NewEmailKey", typeof (String));
			ds.Tables[TableName].Columns.Add("NewEmailRequested", typeof (DateTime));
			ds.Tables[TableName].Columns.Add("Comments", typeof (String));
			ds.Tables[TableName].Columns.Add("CreatedDate", typeof (DateTime));
			ds.Tables[TableName].Columns.Add("LastModifiedDate", typeof (DateTime));

			DataRow dr = ds.Tables[TableName].NewRow();

			dr["AccountId"] = AccountId ?? (object) DBNull.Value;
			dr["UserName"] = UserName ?? (object) DBNull.Value;
			dr["Email"] = Email ?? (object) DBNull.Value;
			dr["Password"] = Password ?? (object) DBNull.Value;
			dr["PasswordSalt"] = PasswordSalt ?? (object) DBNull.Value;
			dr["LastLoginDate"] = LastLoginDate ?? (object) DBNull.Value;
			dr["LastLoginIp"] = LastLoginIp ?? (object) DBNull.Value;
			dr["IsActivated"] = IsActivated ?? (object) DBNull.Value;
			dr["IsLockedOut"] = IsLockedOut ?? (object) DBNull.Value;
			dr["LastLockedOutDate"] = LastLockedOutDate ?? (object) DBNull.Value;
			dr["LastLockedOutReason"] = LastLockedOutReason ?? (object) DBNull.Value;
			dr["NewPasswordKey"] = NewPasswordKey ?? (object) DBNull.Value;
			dr["NewPasswordRequested"] = NewPasswordRequested ?? (object) DBNull.Value;
			dr["NewEmail"] = NewEmail ?? (object) DBNull.Value;
			dr["NewEmailKey"] = NewEmailKey ?? (object) DBNull.Value;
			dr["NewEmailRequested"] = NewEmailRequested ?? (object) DBNull.Value;
			dr["Comments"] = Comments ?? (object) DBNull.Value;
			dr["CreatedDate"] = CreatedDate ?? (object) DBNull.Value;
			dr["LastModifiedDate"] = LastModifiedDate ?? (object) DBNull.Value;

			ds.Tables[TableName].Rows.Add(dr);
		}

		protected void MapFrom(DataRow dr)
		{
			AccountId = dr["AccountId"] != DBNull.Value ? Convert.ToInt32(dr["AccountId"]) : AccountId = null;
			UserName = dr["UserName"] != DBNull.Value ? Convert.ToString(dr["UserName"]) : UserName = null;
			Email = dr["Email"] != DBNull.Value ? Convert.ToString(dr["Email"]) : Email = null;
			Password = dr["Password"] != DBNull.Value ? Convert.ToString(dr["Password"]) : Password = null;
			PasswordSalt = dr["PasswordSalt"] != DBNull.Value ? Convert.ToString(dr["PasswordSalt"]) : PasswordSalt = null;
			LastLoginDate = dr["LastLoginDate"] != DBNull.Value ? Convert.ToDateTime(dr["LastLoginDate"]) : LastLoginDate = null;
			LastLoginIp = dr["LastLoginIp"] != DBNull.Value ? Convert.ToString(dr["LastLoginIp"]) : LastLoginIp = null;
			IsActivated = dr["IsActivated"] != DBNull.Value ? Convert.ToBoolean(dr["IsActivated"]) : IsActivated = null;
			IsLockedOut = dr["IsLockedOut"] != DBNull.Value ? Convert.ToBoolean(dr["IsLockedOut"]) : IsLockedOut = null;
			LastLockedOutDate = dr["LastLockedOutDate"] != DBNull.Value
			                    	? Convert.ToDateTime(dr["LastLockedOutDate"])
			                    	: LastLockedOutDate = null;
			LastLockedOutReason = dr["LastLockedOutReason"] != DBNull.Value
			                      	? Convert.ToString(dr["LastLockedOutReason"])
			                      	: LastLockedOutReason = null;
			NewPasswordKey = dr["NewPasswordKey"] != DBNull.Value
			                 	? Convert.ToString(dr["NewPasswordKey"])
			                 	: NewPasswordKey = null;
			NewPasswordRequested = dr["NewPasswordRequested"] != DBNull.Value
			                       	? Convert.ToDateTime(dr["NewPasswordRequested"])
			                       	: NewPasswordRequested = null;
			NewEmail = dr["NewEmail"] != DBNull.Value ? Convert.ToString(dr["NewEmail"]) : NewEmail = null;
			NewEmailKey = dr["NewEmailKey"] != DBNull.Value ? Convert.ToString(dr["NewEmailKey"]) : NewEmailKey = null;
			NewEmailRequested = dr["NewEmailRequested"] != DBNull.Value
			                    	? Convert.ToDateTime(dr["NewEmailRequested"])
			                    	: NewEmailRequested = null;
			Comments = dr["Comments"] != DBNull.Value ? Convert.ToString(dr["Comments"]) : Comments = null;
			CreatedDate = dr["CreatedDate"] != DBNull.Value ? Convert.ToDateTime(dr["CreatedDate"]) : CreatedDate = null;
			LastModifiedDate = dr["LastModifiedDate"] != DBNull.Value
			                   	? Convert.ToDateTime(dr["LastModifiedDate"])
			                   	: LastModifiedDate = null;

			FillPermissions();
		}

		private static List<Account> MapFrom(DataSet ds)
		{
			// Initialise Collection.
			List<Account> objects = new List<Account>();

			// Validation.
			if (ds == null)
				throw new ApplicationException("Cannot map to dataset null.");
			
			if (ds.Tables[TableName].Rows.Count == 0)
				return objects;

			if (ds.Tables[TableName] == null)
				throw new ApplicationException("Cannot find table [dbo].[Account] in DataSet.");

			if (ds.Tables[TableName].Rows.Count < 1)
				throw new ApplicationException("Table [dbo].[Account] is empty.");

			// Map DataSet to Instance.
			foreach (DataRow dr in ds.Tables[TableName].Rows)
			{
				var instance = new Account();
				instance.MapFrom(dr);
				objects.Add(instance);
			}

			// Return collection.
			return objects;
		}

		#endregion

		#region CRUD Methods

		internal static Account Get(Int32 accountId)
		{
			Account instance = new Account();

			Database db = DatabaseFactory.CreateDatabase();
			const string sqlCommand = "[dbo].gspAccount_SELECT";
			using (DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand, accountId))
			{
				using (DataSet ds = db.ExecuteDataSet(dbCommand))
				{
					if (ds == null || ds.Tables[0].Rows.Count == 0)
						throw new ApplicationException(String.Format("Could not get Account ID:{0} from Database.", accountId));
					// Return results.
					ds.Tables[0].TableName = TableName;

					instance.MapFrom(ds.Tables[0].Rows[0]);
				}
			}
			return instance;
		}

		#region INSERT

		private void Insert(String userName, String email, String password, String passwordSalt, DateTime? lastLoginDate,
		                   String lastLoginIp, Boolean? isActivated, Boolean? isLockedOut, DateTime? lastLockedOutDate,
		                   String lastLockedOutReason, String newPasswordKey, DateTime? newPasswordRequested, String newEmail,
		                   String newEmailKey, DateTime? newEmailRequested, String comments, DateTime? createdDate,
		                   DateTime? lastModifiedDate, DbTransaction transaction = null)
		{
			Database db = DatabaseFactory.CreateDatabase();
			const string sqlCommand = "[dbo].gspAccount_INSERT";
			using (DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand, userName, email, password, passwordSalt, lastLoginDate, lastLoginIp, isActivated, isLockedOut, lastLockedOutDate, lastLockedOutReason, newPasswordKey, newPasswordRequested, newEmail, newEmailKey, newEmailRequested, comments, createdDate, lastModifiedDate))
			{
				AccountId = Convert.ToInt32(transaction == null ? db.ExecuteScalar(dbCommand) : db.ExecuteScalar(dbCommand, transaction));
			}
		}

		/// <summary>
		/// Insert current Account to database.
		/// </summary>
		/// <param name="transaction">optional SQL Transaction</param>
		private void Insert(DbTransaction transaction = null)
		{
			Insert(UserName, Email, Password, PasswordSalt, LastLoginDate, LastLoginIp, IsActivated, IsLockedOut,
			       LastLockedOutDate, LastLockedOutReason, NewPasswordKey, NewPasswordRequested, NewEmail, NewEmailKey,
			       NewEmailRequested, Comments, CreatedDate, LastModifiedDate, transaction);
		}

		#endregion

		#region UPDATE

		private static void Update(Int32? accountId, String userName, String email, String password, String passwordSalt,
		                          DateTime? lastLoginDate, String lastLoginIp, Boolean? isActivated, Boolean? isLockedOut,
		                          DateTime? lastLockedOutDate, String lastLockedOutReason, String newPasswordKey,
		                          DateTime? newPasswordRequested, String newEmail, String newEmailKey,
		                          DateTime? newEmailRequested, String comments, DateTime? createdDate,
		                          DateTime? lastModifiedDate, DbTransaction transaction = null)
		{
			Database db = DatabaseFactory.CreateDatabase();
			const string sqlCommand = "[dbo].gspAccount_UPDATE";
			using (DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand))
			{
				db.DiscoverParameters(dbCommand);
				dbCommand.Parameters["@accountId"].Value = accountId;
				dbCommand.Parameters["@userName"].Value = userName;
				dbCommand.Parameters["@email"].Value = email;
				dbCommand.Parameters["@password"].Value = password;
				dbCommand.Parameters["@passwordSalt"].Value = passwordSalt;
				dbCommand.Parameters["@lastLoginDate"].Value = lastLoginDate;
				dbCommand.Parameters["@lastLoginIp"].Value = lastLoginIp;
				dbCommand.Parameters["@isActivated"].Value = isActivated;
				dbCommand.Parameters["@isLockedOut"].Value = isLockedOut;
				dbCommand.Parameters["@lastLockedOutDate"].Value = lastLockedOutDate;
				dbCommand.Parameters["@lastLockedOutReason"].Value = lastLockedOutReason;
				dbCommand.Parameters["@newPasswordKey"].Value = newPasswordKey;
				dbCommand.Parameters["@newPasswordRequested"].Value = newPasswordRequested;
				dbCommand.Parameters["@newEmail"].Value = newEmail;
				dbCommand.Parameters["@newEmailKey"].Value = newEmailKey;
				dbCommand.Parameters["@newEmailRequested"].Value = newEmailRequested;
				dbCommand.Parameters["@comments"].Value = comments;
				dbCommand.Parameters["@createdDate"].Value = createdDate;
				dbCommand.Parameters["@lastModifiedDate"].Value = lastModifiedDate;

				if (transaction == null)
					db.ExecuteNonQuery(dbCommand);
				else
					db.ExecuteNonQuery(dbCommand, transaction);
			}
		}

		private static void Update(Account account)
		{
			account.Update();
		}

		private static void Update(Account account, DbTransaction transaction)
		{
			account.Update(transaction);
		}

		/// <summary>
		/// Updates changes to the database.
		/// </summary>
		/// <param name="transaction">optional SQL Transaction</param>
		private void Update(DbTransaction transaction = null)
		{
			Database db = DatabaseFactory.CreateDatabase();
			const string sqlCommand = "[dbo].gspAccount_UPDATE";
			using (DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand))
			{
				db.DiscoverParameters(dbCommand);
				dbCommand.Parameters["@accountId"].SourceColumn = "AccountId";
				dbCommand.Parameters["@userName"].SourceColumn = "UserName";
				dbCommand.Parameters["@email"].SourceColumn = "Email";
				dbCommand.Parameters["@password"].SourceColumn = "Password";
				dbCommand.Parameters["@passwordSalt"].SourceColumn = "PasswordSalt";
				dbCommand.Parameters["@lastLoginDate"].SourceColumn = "LastLoginDate";
				dbCommand.Parameters["@lastLoginIp"].SourceColumn = "LastLoginIp";
				dbCommand.Parameters["@isActivated"].SourceColumn = "IsActivated";
				dbCommand.Parameters["@isLockedOut"].SourceColumn = "IsLockedOut";
				dbCommand.Parameters["@lastLockedOutDate"].SourceColumn = "LastLockedOutDate";
				dbCommand.Parameters["@lastLockedOutReason"].SourceColumn = "LastLockedOutReason";
				dbCommand.Parameters["@newPasswordKey"].SourceColumn = "NewPasswordKey";
				dbCommand.Parameters["@newPasswordRequested"].SourceColumn = "NewPasswordRequested";
				dbCommand.Parameters["@newEmail"].SourceColumn = "NewEmail";
				dbCommand.Parameters["@newEmailKey"].SourceColumn = "NewEmailKey";
				dbCommand.Parameters["@newEmailRequested"].SourceColumn = "NewEmailRequested";
				dbCommand.Parameters["@comments"].SourceColumn = "Comments";
				dbCommand.Parameters["@createdDate"].SourceColumn = "CreatedDate";
				dbCommand.Parameters["@lastModifiedDate"].SourceColumn = "LastModifiedDate";

				using (DataSet ds = new DataSet())
				{
					MapTo(ds);
					ds.AcceptChanges();
					ds.Tables[0].Rows[0].SetModified();
					if (transaction == null)
						db.UpdateDataSet(ds, TableName, null, dbCommand, null, UpdateBehavior.Standard);
					else
						db.UpdateDataSet(ds, TableName, null, dbCommand, null, transaction);
				}
			}
		}

		#endregion

		#region DELETE

		private static void Delete(Int32? accountId, DbTransaction transaction)
		{
			Database db = DatabaseFactory.CreateDatabase();
			const string sqlCommand = "[dbo].gspAccount_DELETE";
			using (DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand, accountId))
			{
				if (transaction != null)
				{
					db.ExecuteNonQuery(dbCommand, transaction);
				}
				else
				{
					db.ExecuteNonQuery(dbCommand);
				}
			}
		}

		/// <summary>
		/// Delete current Account from database.
		/// </summary>
		/// <param name="transaction">optional SQL Transaction</param>
		private void Delete(DbTransaction transaction = null)
		{
			Database db = DatabaseFactory.CreateDatabase();
			const string sqlCommand = "[dbo].gspAccount_DELETE";
			using (DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand, AccountId))
			{
				if (transaction != null)
				{
					db.ExecuteNonQuery(dbCommand, transaction);
				}
				else
				{
					db.ExecuteNonQuery(dbCommand);
				}
			}
			AccountId = null;
		}

		#endregion

		#region SEARCH

		private static List<Account> Search(Int32? accountId = null, String userName = null, String email = null, String password = null, String passwordSalt = null,
		                               DateTime? lastLoginDate = null, String lastLoginIp = null, Boolean? isActivated = null, Boolean? isLockedOut = null,
		                               DateTime? lastLockedOutDate = null, String lastLockedOutReason = null, String newPasswordKey = null,
		                               DateTime? newPasswordRequested = null, String newEmail = null, String newEmailKey = null,
		                               DateTime? newEmailRequested = null, String comments = null, DateTime? createdDate = null,
		                               DateTime? lastModifiedDate = null)
		{
			Database db = DatabaseFactory.CreateDatabase();
			const string sqlCommand = "[dbo].gspAccount_SEARCH";
			using (DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand, accountId, userName, email, password, passwordSalt, lastLoginDate, lastLoginIp, isActivated, isLockedOut, lastLockedOutDate, lastLockedOutReason, newPasswordKey, newPasswordRequested, newEmail, newEmailKey, newEmailRequested, comments, createdDate, lastModifiedDate))
			{
				using (DataSet ds = db.ExecuteDataSet(dbCommand))
				{
					ds.Tables[0].TableName = TableName;
					return MapFrom(ds);
				}
			}
		}


		private static List<Account> Search(Account searchObject)
		{
			return Search(searchObject.AccountId, searchObject.UserName, searchObject.Email, searchObject.Password,
			              searchObject.PasswordSalt, searchObject.LastLoginDate, searchObject.LastLoginIp,
			              searchObject.IsActivated, searchObject.IsLockedOut, searchObject.LastLockedOutDate,
			              searchObject.LastLockedOutReason, searchObject.NewPasswordKey, searchObject.NewPasswordRequested,
			              searchObject.NewEmail, searchObject.NewEmailKey, searchObject.NewEmailRequested, searchObject.Comments,
			              searchObject.CreatedDate, searchObject.LastModifiedDate);
		}

		#endregion

		#endregion

		#endregion
	}
}